package services

import (
	"api/app/wms/conf"
	"api/app/wms/models"
	"api/public/global"
	"gitee.com/dreamwood/ez"
	"gorm.io/gorm"
	"time"
)

func CreateChangeLog(itemId int, ioType int) {
	crud := models.NewChangeLogCrud()
	start := ez.GetDayStart(time.Now())
	end := ez.GetDayEnd(time.Now())
	find, e := crud.FindOneBy(ez.M{"itemId": itemId, "ioType": ioType, "createAt__gt": start, "createAt__lt": end}, nil)
	if e != nil && e.Error() != "record not found" {
		println(e.Error())
		return
	}
	if find.Id > 0 {
		find.State = 0
	}
	find.ItemId = itemId
	find.IoType = ioType
	find.Save(false)
}

// CreateSummary 创建当前之前的汇总,不会有重复的冗余的操作，非实时
func CreateSummary() {
	crud := models.NewChangeLogCrud()
	//只处理今天以前的信息
	dayStart := ez.GetDayStart(time.Now())
	rows, e := crud.FindBy(ez.M{"state": 0, "createAt__lt": dayStart}, []string{"id"}, 0, 10)
	if e != nil {
		return
	}
	for _, row := range rows {
		if row.IoType == conf.ChangeLogIn {
			SummaryInLog(row)
		}
		if row.IoType == conf.ChangeLogOut {
			SummaryOutLog(row)
		}
	}
}

// CreateSummaryManual 实时创建汇总，有物品重复出入库时会做无用功
func CreateSummaryManual() {
	crud := models.NewChangeLogCrud()
	rows, e := crud.FindBy(ez.M{"state": 0}, []string{"id"}, 0, 10)
	if e != nil {
		return
	}
	for _, row := range rows {
		if row.IoType == conf.ChangeLogIn {
			SummaryInLog(row)
		}
		if row.IoType == conf.ChangeLogOut {
			SummaryOutLog(row)
		}
	}
}

func SummaryInLog(log *models.ChangeLog) {
	crud := models.NewInLogCrud()
	dayStart := time.Date(log.CreateAt.Year(), log.CreateAt.Month(), log.CreateAt.Day(), 0, 0, 0, 0, time.Local)
	dayEnd := time.Date(log.CreateAt.Year(), log.CreateAt.Month(), log.CreateAt.Day(), 24, 0, 0, 0, time.Local)

	rows, e := crud.FindBy(
		ez.M{
			"itemId":       log.ItemId,
			"createAt__gt": dayStart,
			"createAt__lt": dayEnd,
		},
		nil, 0, 0)
	if e != nil {
		return
	}
	toSave := make(map[int]float64)
	for _, row := range rows {
		_, ok := toSave[row.TypeId]
		if !ok {
			toSave[row.TypeId] = 0
		}
		toSave[row.TypeId] += row.NumIn
	}

	//汇总数据
	e = global.DB.Transaction(func(tx *gorm.DB) error {
		//写入记录
		for id, sum := range toSave {
			y := time.Now().Year()
			m := int(time.Now().Month())
			d := time.Now().Day()
			ymd := y*10000 + m*100 + d

			en := &models.Summary{}
			en.ItemId = log.ItemId
			en.Num = sum
			en.Y = y
			en.M = m
			en.D = d
			en.Ymd = ymd
			en.IoType = conf.ChangeLogIn
			t := new(models.IOType)
			t.Id = id
			t.Read()
			en.TypeId = id
			en.TypeName = t.Name
			now := time.Now()
			en.CreateAt = &now
			rst := tx.Save(en)
			if rst.Error != nil {
				return rst.Error
			}
		}
		//更新ChangeLog
		log.State = 1
		rst := tx.Select("State").Updates(log)
		if rst.Error != nil {
			return rst.Error
		}

		return nil
	})

}

func SummaryOutLog(log *models.ChangeLog) {
	crud := models.NewOutLogCrud()
	dayStart := time.Date(log.CreateAt.Year(), log.CreateAt.Month(), log.CreateAt.Day(), 0, 0, 0, 0, time.Local)
	dayEnd := time.Date(log.CreateAt.Year(), log.CreateAt.Month(), log.CreateAt.Day(), 24, 0, 0, 0, time.Local)

	rows, e := crud.FindBy(
		ez.M{
			"itemId":       log.ItemId,
			"createAt__gt": dayStart,
			"createAt__lt": dayEnd,
		},
		nil, 0, 0)
	if e != nil {
		return
	}
	toSave := make(map[int]float64)
	for _, row := range rows {
		_, ok := toSave[row.TypeId]
		if !ok {
			toSave[row.TypeId] = 0
		}
		toSave[row.TypeId] += row.Num
	}

	//汇总数据
	e = global.DB.Transaction(func(tx *gorm.DB) error {
		//写入记录
		for id, sum := range toSave {
			//en := &models.Summary{}
			//en.ItemId = id
			//en.Num = sum
			//en.Y = time.Now().Year()
			//en.D = time.Now().Day()
			//en.M = int(time.Now().Month())
			//en.Ymd = en.Y*10000 + en.M*100 + en.D
			//t := new(models.IOType)
			//t.Id = id
			//t.Read()
			//en.TypeName = t.Name
			//now := time.Now()
			//en.CreateAt = &now
			//rst := tx.Save(en)
			//if rst.Error != nil {
			//	return rst.Error
			//}
			//
			y := time.Now().Year()
			m := int(time.Now().Month())
			d := time.Now().Day()
			ymd := y*10000 + m*100 + d

			en := &models.Summary{}
			en.ItemId = log.ItemId
			en.Num = sum
			en.Y = y
			en.M = m
			en.D = d
			en.Ymd = ymd
			en.IoType = conf.ChangeLogOut
			t := new(models.IOType)
			t.Id = id
			t.Read()
			en.TypeId = id
			en.TypeName = t.Name
			now := time.Now()
			en.CreateAt = &now
			rst := tx.Save(en)
			if rst.Error != nil {
				return rst.Error
			}

		}
		//更新ChangeLog
		log.State = 1
		rst := tx.Select("State").Updates(log)
		if rst.Error != nil {
			return rst.Error
		}
		return nil
	})
}

func GetSummaryRelatedItemIds(start time.Time, end time.Time) []struct {
	ItemId int
} {
	db := global.DB
	relatedItemIds := make([]struct {
		ItemId int
	}, 0)
	db.Model(&models.Summary{}).
		Select("item_id").
		Group("item_id").
		Where("create_at > ?", start).
		Where("create_at < ?", end).
		Find(&relatedItemIds)
	return relatedItemIds
}
func CreateSummaryTableData(start time.Time, end time.Time) []*SummaryItemData {
	relatedItemIds := GetSummaryRelatedItemIds(start, end)
	//逐个获取汇总

	data := make([]*SummaryItemData, len(relatedItemIds))
	for index, row := range relatedItemIds {
		//生成项目的汇总数据
		//CreateSummaryForItem(row.ItemId,start,end)
		data[index] = CreateSummaryForItem(row.ItemId, start, end)
	}
	return data
}

type SummaryTableData struct {
	NumIn  float64
	NumOut float64
}

type SummaryItemData struct {
	Item *models.ItemSku
	Cols map[int]*SummaryTableData
}

func CreateSummaryForItem(itemId int, start time.Time, end time.Time) *SummaryItemData {

	crudItem := models.NewItemSkuCrud()
	item, _ := crudItem.Find(itemId)
	crud := models.NewSummaryCrud()
	data := SummaryItemData{
		Item: item,
		Cols: map[int]*SummaryTableData{},
	}

	rows, e := crud.FindBy(ez.M{"itemId": itemId, "createAt__gt": start, "createAt__lt": end}, nil, 0, 0)
	if e != nil {
		ez.PrintError(e)
		return nil
	}
	//ez.JsonLog(rows)

	for _, row := range rows {
		_, ok := data.Cols[row.Ymd]
		if !ok {
			data.Cols[row.Ymd] = &SummaryTableData{}
		}
		if row.IoType == conf.ChangeLogIn {
			data.Cols[row.Ymd].NumIn += row.Num
		}
		if row.IoType == conf.ChangeLogOut {
			data.Cols[row.Ymd].NumOut += row.Num
		}
	}
	return &data
}
